#!/usr/bin/python
# -*- coding: utf-8 -*-
import services
import random

class Application(object):

    def __init__(self, protocol, services=services):
        self.protocol_ = protocol
        self.protocol_.set_callback(self.State)
        self.services_ = services

    def State(self):
        pass

    def Run(self):
        pass

class TokenRing(Application):
    
    def __init__(self, protocol, state_size = 1, max_count = 5,
                 step_count = 1, payload = lambda: None,
                 services=services, random=random):
        Application.__init__(self, protocol, services)
        self.ring_ = self.services_.virtualring()
        self.ring_.set_comm(self.protocol_)
        self.counter_ = 1
        self.max_count_ = max_count
        self.state_size_ = state_size
        self.step_count_ = step_count
        self.random_ = random
        self.payload_ = payload
        
    def State(self):
        return([self.counter_, 
                [self.random_.randint(0,10) 
                 for i in xrange(0, self.state_size_)]]) 

    def Run(self):
        t = self.services_.timer(self.protocol_)
        self.protocol_.take_basic_checkpoint()
        if self.protocol_.get_pid() == 1:
            self.ring_.send_prev([0, 1, -1])

        while (self.counter_ < self.max_count_):
            origin, msg = self.protocol_.recv_message()
            if msg[0] == 0:
                self.counter_ = msg[1] + 1
                if (self.counter_ < self.max_count_):
                    if self.counter_ % self.step_count_ == 0:
                        self.protocol_.take_basic_checkpoint()
                    self.ring_.send_prev([0, self.counter_, -1])
                    random_peer = self.random_.sample(
                        [i for i in self.protocol_.get_hosts() if
                         i != self.protocol_.get_pid()], 1)
                    for i in random_peer:
                        self.protocol_.send_message(
                            i, [1, self.payload_()])
                else:
                    if msg[2] == -1:
                        self.ring_.send_prev([0, self.counter_, 
                                        self.protocol_.get_pid()])
                    elif self.ring_.get_prev() != msg[2]:
                        self.ring_.send_prev([0, self.counter_, msg[2]])
                    for i in [i for i in self.protocol_.get_hosts() if
                              i != self.protocol_.get_pid()]:
                        self.protocol_.close_channel(i)
                        
        t.send_timestamp()

# File System Abstraction Factory
def ApplicationAF(name, *args, **kargs):
    app = {'tokenring': TokenRing }
    if name in ('tokenring'):
        return app[name](*args, **kargs)
    else:
        raise(ValueError, 'Inexistent Application')
    

    

